from base64 import b64encode
from hashlib import md5
from os.path import exists
from datetime import date
from random import randrange
import time

from flask import Blueprint


from zvms.models import Volunteer, StuVol, ClassVol, Student
from zvms.util import *
from zvms.deco import *
from zvms.res import *

volunteer = Blueprint('volunteer', __name__)

@volunteer.route('/volunteer/list', methods=['GET'])
@Deco
def getVolunteerList(json_data, token_data):
    r = list(Volunteer.query.select('status', 'stuMax', markdown='description', volId='id', volName='name', volDate='date', volTime='time'))
    if not r:
        return error('当前无义工')
    r = sorted(r, key=lambda x: x["date"], reverse=True)
    return success('获取成功', volunteer=r)

@volunteer.route('/volunteer/fetch/<int:volId>', methods=['GET'])
@Deco
def getVolunteer(volId, json_data, token_data):
    return success('获取成功', **Volunteer.query.get_or_error(volId).select('stuMax', 'status', markdown='description', volName='name', 
        volDate='date', volTime='time', nowStuCount='stuNow', volTimeInside='inside', volTimeOutside='outside', volTimeLarge='large'))

# 判断班级人数是否超限
# 义工vol，在cls班里再报名dlt个人
def checkStuLimit(vol,cls,dlt): # 过了
    # print("Checking:",vol,cls,dlt)
    cv = ClassVol.query.get(vol)
    if not cv:
        return False, error(f'班级{cls}无法报名该义工')
    if cv.nowStuCount + dlt > cv.stuMax:
        return False, error(f'班级{cls}人数超限')    
    return True, {}

# 判断义工人数是否合法
# 传入字典（直接用postdata就好）至少有以下内容：
# {"stuMax":233,"class":[{"id":202001,"stuMax":10},...]}
def checkStudentCount(js): # 过了
    # 传入json
    # 如果最大人数大于每个班最大人数之和那么永远报不满
    mx=js["stuMax"]
    for i in js["class"]: mx-=i["stuMax"]
    return mx<=0

@volunteer.route('/volunteer/signup/<int:volId>', methods=['POST'])
@Deco
def signupVolunteer(volId, json_data, token_data):
    vol = Volunteer.query.get_or_error(volId)
    if len(json_data['stulst']) > vol.stuMax - vol.nowStuCount:
        return error('人数超限')
    if time.time() > time.mktime(time.strptime(vol.volDate + ' ' + vol.volTime, '%Y-%m-%d %H:%M')):
        return error('义工时间已过')
    num = {}
    for i in json_data['stulst']:
        if not checkPermission(token_data['class'], token_data['permission'], i):
            return error('权限不足: 学生列表中有别班学生')
        if StuVol.query.get(volId, i):
            return error(f'学生{i}已报名, 不可重复报名')
        cur = i // 100
        num[cur] = num[cur] + 1 if cur in num else 1
    for i in num:
        fl, r = checkStuLimit(volId, i, num[i])
        if not fl:
            return r
    vol.nowStuCount += len(json_data['stulst'])
    for i in num:
        ClassVol.query.get(volId, i).nowStuCount += num[i]
    for i in json_data['stulst']:
        StuVol(
            volId=volId,
            stuId=i,
            status=STATUS_WAITING,
            volTimeInside=0,
            volTimeOutside=0,
            volTImeLarge=0,
            thought=''
        ).insert()
    return success('报名成功')

def create(**kwargs):
    return Volunteer(
        volName=kwargs['name'],
        volDate=kwargs['date'],
        volTime=kwargs['time'],
        stuMax=kwargs['stuMax'],
        nowStuCount=kwargs['stucount'],
        description=kwargs['description'],
        status=VOLUNTEER_WAITING,
        volTimeInside=kwargs['inside'],
        volTimeOutside=kwargs['outside'],
        volTimeLarge=kwargs['large'],
        holderId=kwargs['userid']
    ).insert().volId

@volunteer.route('/volunteer/create', methods=['POST'])
@Deco
def createVolunteer(json_data, token_data):
    if token_data['permission'] not in (PMS_TEACHER, PMS_MANAGER, PMS_SYSTEM):
        return error('权限不足')
    if not checkStudentCount(json_data):
        return error('最大人数不符合要求: 义工永远无法报满')
    if json_data['inside'] < 0 or json_data['outside'] < 0 or json_data['large'] < 0:
        return error('义工时间不能为负数')
    id = create(**json_data, stucount=0, userid=token_data['userid'])
    for i in json_data['class']:
        ClassVol(
            volId=id,
            class_=i['id'],
            stuMax=i['stuMax'],
            nowStuCount=0
        )
    return success('创建成功')

@volunteer.route('/volunteer/signerList/<int:volId>', methods=['GET'])
@Deco
def getSignerList(volId, json_data, token_data):
    vol = Volunteer.query.get(volId)
    signers = None
    if not vol or not (signers := vol.signers):
        return success('当前义工无人报名')
    return success('获取成功', result=signers)

@volunteer.route('/volunteer/unaudited', methods=['GET'])
@Deco
def getUnaudited(json_data, token_data):
    r = list(StuVol.query.filter(StuVol.status == STATUS_WAITING, StuVol.thought != '').select('volId', 'stuId', 'markdown'))
    for i in r:
        r['picture'] = []
    if not r:
        return success('全部审核完毕')
    return success('获取成功', result=r)

@volunteer.route('/volunteer/unaudited/list', methods=['GET'])
@Deco
def listUnaudited(json_data, token_data):
    r = list(StuVol.query.filter(StuVol.status == STATUS_WAITING, StuVol.thought != '').select('volId', 'stuId'))
    if not r:
        return success('全部审核完毕')
    return success('获取成功', result=r)

@volunteer.route('/volunteer/unaudited/<int:stuId>/<int:volId>', methods=['GET'])
@Deco
def fetchUnaudited(stuId, volId, json_data, token_data):
    sv = StuVol.query.filter_by(volId=volId, stuId=stuId, status=STATUS_WAITING).filter(StuVol.thought != '').first()
    if not sv:
        return error('未查询到相关记录')
    pics = []
    for i, s in enumerate(sv.picture.split(',')):
        pics.append({'id': i, 'src': s})
    return success('获取成功', result={'thought': sv.markdown, 'picture': pics})

@volunteer.route('/volunteer/audit/<int:volId>', methods=['POST'])
@Deco
def auditThought(volId, json_data, token_data):
    if token_data['permission'] not in (PMS_MANAGER, PMS_SYSTEM):
        return error('权限不足')
    for i in json_data['thought']:
        stuId = i['stuId']
        thought = StuVol.query.get_or_error((volId, stuId))
        if thought.status == STATUS_ACCEPT:
            return error(f'学生{stuId}已过, 不可重复提交')
        if thought.status == STATUS_REJECT:
            return error(f'学生{stuId}不可重新提交')
        if i['status'] != STATUS_ACCEPT:
            thought.thought = ''
        thought.update(
            status=i['status'],
            volTimeInside=i['inside'],
            volTimeOutside=i['outside'],
            volTimeLarge=i['large']
        )
        Student.query.get(stuId).update(
            volTimeInside=incr(int(i['inside'])),
            volTimeOutside=incr(int(i['outside'])),
            volTimeLarge=incr(int(i['large']))
        )
        return success('审核成功')

@volunteer.route('/volunteer/holiday', methods=['POST'])
@Deco
def holidayVolunteer(json_data, token_data):
    for i in json_data['stuId']:
        if token_data['class'] != int(i) // 100:
            return error('权限不足: 学生列表中有别班学生')
    stucount=len(json_data['stuId'])
    id = create(**json_data, stuMax=stucount, stucount=stucount, userid=token_data['userid'])
    ClassVol(
        volId=id,
        class_=token_data['class'],
        stuMax=stucount,
        nowStuCount=stucount,
    ).insert()
    for i in json_data['stuId']:
        StuVol(
            volId=id,
            stuId=i,
            status=STATUS_WAITING,
            volTimeInside=0,
            volTimeOutside=0,
            volTimeLarge=0,
            thought=''
        ).insert()
    return success('提交成功')

@volunteer.route('/volunteer/thought/<int:volId>', methods=['POST'])
@Deco
def submitThougt(volId, json_data, token_data):
    for i in json_data['thought']:
        if not checkPermission(token_data['class'], token_data['permission'], i['stuId']):
            return error('权限不足: 学生列表中有别班学生')
    for i in json_data['thought']:
        stuId = i['stuId']
        today = date.today()
        student = Student.query.get(stuId)
        rand = randrange(2)
        if (FOOLS_DAY and ((today.month == 4 and today.day == 1) or rand == 0) and student.activated_until < today and 
            sum((student.volTimeInside, student.volTimeOutside, student.volTimeLarge)) >= 180):
            return error(f'学生{stuId}账户未激活, 只能做3小时义工')
        thought = StuVol.query.get_or_error((volId, stuId))
        if thought.status == STATUS_ACCEPT:
            return error(f'学生{stuId}已过审, 不可重复提交')
        if thought.status == STATUS_REJECT:
            return error(f'学生{stuId}不可重新提交')
        pics = i['pictures']
        pics_md5 = []
        for pic in pics:
            t = md5()
            t.update(pic.encode('utf-8'))
            target = t.hexdigest()
            pics_md5.append(target)
            path = f'{STATIC_FOLDER}/pics/{target}.jpg'
            if not exists(path):
                with open (path, 'wb') as f:
                    f.write(b64encode(pic))
        thought.update(
            thought=i['content'],
            status=STATUS_WAITING,
            picture=','.join(pics_md5)
        )
    return success('提交成功')
